package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.common.query.QueryObject;
import cn.wolfcode.luowowo.search.query.StrategySearchQueryObject;
import cn.wolfcode.luowowo.search.repository.StrategyTemplateRepository;
import cn.wolfcode.luowowo.search.service.IStrategyTemplateSearchService;
import cn.wolfcode.luowowo.search.template.StrategyTemplate;
import cn.wolfcode.luowowo.search.vo.StatisVO;
import com.alibaba.dubbo.config.annotation.Service;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.search.MultiMatchQuery;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.bucket.composite.*;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;

import java.util.*;

@Service
public class StrategyTemplateSearchServiceImpl implements IStrategyTemplateSearchService {

    //es 依然使用spring-data-jpa

    //repository 封装了template
    //template 封装了 client

    @Autowired
    private StrategyTemplateRepository repository;
    @Autowired
    private ElasticsearchTemplate template;
    @Autowired
    private TransportClient client;  //java操作es的第三方客户端


    @Override
    public void saveOrUpdate(StrategyTemplate template) {
        repository.save(template);
    }

    @Override
    public List<StatisVO> getGroupStatisVOS(int type) {
        if (type == StrategySearchQueryObject.THEME) {
            return this.getStatisVOS("themeGroup", "themeId", "themeName", null);
        } else if (type == StrategySearchQueryObject.CHINA) {
            return this.getStatisVOS("provinceGroup", "provinceId", "provinceName", null);
        } else if (type == StrategySearchQueryObject.ABROAD) {

            //设置一个过滤条件排除掉中国
            BoolQueryBuilder bq = new BoolQueryBuilder();
            //条件设置在下面两个维度参数中
            bq.mustNot(QueryBuilders.termQuery("countryName", "中国"));
            return this.getStatisVOS("countryGroup", "countryId", "countryName", bq);
        }
        return null;
    }

    @Override
    public Page query(StrategySearchQueryObject qo) {

        NativeSearchQueryBuilder nb = new NativeSearchQueryBuilder();

        //记住减一
        nb.withPageable(PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize()));

        nb.withSort(SortBuilders.fieldSort(qo.getOrderBy()).order(SortOrder.DESC));

        //主题

        if(qo.getType() == StrategySearchQueryObject.THEME){
            nb.withQuery(QueryBuilders.termQuery("themeId",qo.getTypeValue()));
        }else if(qo.getType() == StrategySearchQueryObject.CHINA ){
            nb.withQuery(QueryBuilders.termQuery("provinceId",qo.getTypeValue()));
        }else if(qo.getType() == StrategySearchQueryObject.ABROAD ){
            nb.withQuery(QueryBuilders.termQuery("countryId",qo.getTypeValue()));
        }


        return repository.search(nb.build());


    }

//    @Override
//    public Page query(StrategySearchQueryObject qo) {
//
//        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//
//        if(qo.getType() == StrategySearchQueryObject.CONDITION_TYPE_ABROAD){
//            //countryId
//            boolQuery.must(QueryBuilders.termQuery("countryId", qo.getTypeValue()));
//        }else if(qo.getType() == StrategySearchQueryObject.CONDITION_TYPE_UN_ABROAD){
//            //provinceId
//            boolQuery.must(QueryBuilders.termQuery("provinceId", qo.getTypeValue()));
//        }else if(qo.getType() == StrategySearchQueryObject.CONDITION_TYPE_THEME){
//            //themeid
//            boolQuery.must(QueryBuilders.termQuery("themeId", qo.getTypeValue()));
//        }
//
//        return repository.search(boolQuery,qo.getPageable());
//    }

    @Override
    public List<Map<String, Object>> getThemeCommedsTop10() {

        List<Map<String, Object>> result = new ArrayList<>();

        //先获取所有的攻略推荐
        List<StatisVO> themes = this.getGroupStatisVOS(StrategySearchQueryObject.THEME);

        //截取前十个
        if (themes.size() >= 10) {
            themes = themes.subList(0, 10);
        }

        for (StatisVO theme : themes) {

            //使用map存放
            Map<String, Object> map = new HashMap<>();
            map.put("theme", theme);
            map.put("dests", this.getDestListByThemeId(theme.getId()));

            //设置近集合中
            result.add(map);
        }

        return result;
    }

    @Override
    public List<StrategyTemplate> findByDestName(String destName) {
        return repository.findByDestName(destName);

    }

    /**
     * 根据主题ID获取目的地集合
     *
     * @param themeId
     * @return
     */
    public List<StatisVO> getDestListByThemeId(Long themeId) {

        //查询出对应的主题下的攻略所有的目的地
        Iterable<StrategyTemplate> iterables = repository.search(QueryBuilders.termQuery("themeId", themeId));

        //单纯的使用Vo来存放数据
        List<StatisVO> dests = new ArrayList<>();

        //这才是个迭代器
        Iterator<StrategyTemplate> iterator = iterables.iterator();

        //用来判断去重
        List<String> judge = new ArrayList<>();

        while (iterator.hasNext()) {

            StrategyTemplate template = iterator.next();

            StatisVO vo = new StatisVO();

            vo.setId(template.getDestId());

            vo.setName(template.getDestName());

            //做去重判断
            if (!judge.contains(vo.getName())) {

                judge.add(vo.getName());
                dests.add(vo);
            }

        }
        return dests;
    }

    /**
     * 分类型获取攻略推荐集合
     * @param GroupBy
     * @param field
     * @param t_field
     * @param query
     * @return
     */
    public List<StatisVO> getStatisVOS(String GroupBy, String field, String t_field, QueryBuilder query) {

        List<StatisVO> result = new ArrayList<>();

        //分组维度的集合对象   分组维度 就是分组后每一个  "sources"
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();

        //参数1 分组的名称,我们起的别名
        //参数2 就是分组维度的集合  就是分组的结果集合
        //这个是按照主题分组
        CompositeAggregationBuilder aBuilder = new CompositeAggregationBuilder(GroupBy, sources);

        //分组维度封装的对象  id参数 就是主题id
        TermsValuesSourceBuilder idSource = new TermsValuesSourceBuilder("id");

        //设置这个对象的属性 terms:{"field" : "themeID"}
        idSource.field(field);
        idSource.missingBucket(true);//将不满足条件的buckets结果忽略
        //分组维度这个对象
        sources.add(idSource);

        //第二个分组维度封装对象
        TermsValuesSourceBuilder nameSource = new TermsValuesSourceBuilder("name");

        //设置这个对象的属性 terms:{"field" : "themeName"}
        nameSource.field(t_field);
        nameSource.missingBucket(true);
        sources.add(nameSource);

        //查询操作  查询条件构建
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        //首先,就要设置去哪个索引的哪个类型去找
        builder.withIndices(StrategyTemplate.INDEX_NAME);//设置好索引
        builder.withTypes(StrategyTemplate.TYPE_NAME);//设置好类型
        //这里就是设置查询想要的结果的模块结构,就是上面设置的 CompositeAggregationBuilder 复合的桶聚合查询条件构建
        builder.addAggregation(aBuilder);
        //设置分页的参数 这里不用分页 所以设置为 0 0 但是 jpa的分页规范 不能设置为0 所以只能是 0 1
        //其实就是在设置 size:0 这个条件
        //设置分页参数使用的是 pageResult.of
        builder.withPageable(PageRequest.of(0, 1));


        //设置一个查询条件海外推荐时过滤掉中国
        if (query != null) {
            builder.withQuery(query);
        }


        //执行查询   使用repository 的 search 方法
        //结果是 分组分页类型 需要强转
        AggregatedPage<StrategyTemplate> page = (AggregatedPage<StrategyTemplate>) repository.search(builder.build());

        //再拿里面的aggs 从aggs中拿到 分组结果"themeGroup"
        InternalComposite aggregation = page.getAggregations().get(GroupBy);

        //再拿buckets 循环就能获取到每一个 结果对象
        //这里要用接口接受,实现类修饰符是默认的  不是这个包的 不能用
        for (CompositeAggregation.Bucket bucket : aggregation.getBuckets()) {

            //这里就是每一个结果 取值封装为维度对象即可
            StatisVO statisVO = new StatisVO();
            if (bucket.getKey().get("name") == null) {
                continue;
            }
            statisVO.setId(Long.parseLong(bucket.getKey().get("id").toString()));
            statisVO.setName(bucket.getKey().get("name").toString());
            statisVO.setCount(bucket.getDocCount());

            //添加进结果数组
            result.add(statisVO);

        }

        /**
         * 重写一个比较器来进行list排序
         */
        result.sort(new Comparator<StatisVO>() {
            @Override
            public int compare(StatisVO o1, StatisVO o2) {
                return (int) (o2.getCount() - o1.getCount());
            }
        });

        return result;
    }


}
